#include "LecteurProgramme.h"


LecteurProgramme::LecteurProgramme(string nomFich)
 : Lecteur::Lecteur(nomFich)
{

}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurProgramme::programme() {
	// <programme> ::= { <seq_decl> } debut <seq_inst> fin <EOF>

	if(ls->getSymCour() == "fonction")
	{
		seqDecl();
	}
	sauterSymCour("debut");
	Noeud* si = seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
	return si;
}

////////////////////////////////////////////////////////////////////////////////
void LecteurProgramme::analyse() {
	arbre=programme();
	cout << "Syntaxe correcte." << endl;
}


void LecteurProgramme::seqDecl()				// <seq_decl> ::= <decl_fonction> ; { <decl_fonction> ; }
{
	int i = 0;
	while(ls->getSymCour() == "fonction")
	{
		LecteurFonction* f = new LecteurFonction(ls);
		tf.push_back(f);
		i++;
	}
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurProgramme::affectation() {
// <affectation> ::= <variable> = <expression> | <appel_fonction>

	testerSymCour("<VARIABLE>");
	Noeud* var = ts.chercheAjoute(ls->getSymCour());
	ls->suivant();
	sauterSymCour("=");
	Noeud* exp;
	if( ls->getSymCour() == "fonction" )
	{
        exp = appelFonction();
	}
    else
    {
        exp = expression();
    }
	return new NoeudAffectation(var,exp);
}

Noeud* LecteurProgramme::appelFonction()	// <appel_fonction> ::= fonction <variable> (<variable> { , <variable> } )
{
    vector<Noeud*> p;
    sauterSymCour("fonction");
    testerSymCour("<VARIABLE>");
    Symbole s = ls->getSymCour();
    LecteurFonction* f;
    int i = 0;
    bool trouve = false;
    while( not trouve && i< tf.size() )
    {
        if(  *tf[i]==(s.getChaine()) )
            trouve = true;
        else
            i++;
    }

    if(i < tf.size())
    {
        f = tf[i];
    }
    else
    {
        if( *tf[i]==(s.getChaine()) )
            f = tf[i];
        else
        {
            erreur("fonction non existante");
        }
    }
    sauterSymCour("<VARIABLE>");
    sauterSymCour("(");

    testerSymCour("<VARIABLE>");
    SymboleValue * variable;
    variable = ts.chercheAjoute(ls->getSymCour());
    p.push_back(expression());

    while( ls->getSymCour() == ",")
    {
        sauterSymCour(",");
        variable = ts.chercheAjoute(ls->getSymCour());
        p.push_back(expression());
    }
    sauterSymCour(")");
    return new NoeudInstAppelFonction(dynamic_cast<NoeudSeqInst*> (f->getArbre()), p, f->getParam(), f->getNom());


}

////////////////////////////////////////////////////////////////////////////////
string getIndentedLine(string line, int indentation) {
	string buffer = "";

	for ( int i = 0 ; i < indentation ; i++ )
		buffer = buffer + "\t";

	buffer = buffer + line + "\n";
	return buffer;
}

string LecteurProgramme::getC() {
	buffer			= "";
	int	indent		= 0;

	string comment		= "//";
	string separator	= "---------------------------------------";
	string saut		= "\n\n";

	buffer = buffer + getIndentedLine(comment + "Libs", indent);
	buffer = buffer + getIndentedLine(comment + separator, indent);
	buffer = buffer + getIndentedLine("#include <iostream>", indent);
	buffer = buffer + getIndentedLine("#include <string>", indent);
	buffer = buffer + getIndentedLine(comment + separator, indent);
	buffer = buffer + saut;

    for(int i = 0; i< tf.size(); i++)
	{
	    buffer = buffer + tf[i]->getCode(indent);
	    indent = 0;
	    buffer += saut;
	}

	buffer = buffer + getIndentedLine(comment + "Main function", indent);
	buffer = buffer + getIndentedLine(comment + separator, indent);

	buffer = buffer + getIndentedLine("int main(void) {", indent);
	indent++;
	buffer = buffer + arbre->getCode(indent);
	buffer = buffer + "return EXIT_SUCCESS";
	indent--;

	buffer = buffer + getIndentedLine("}", indent);
	buffer = buffer + getIndentedLine(comment + separator + saut, indent);



	return buffer;
}
